#include "Application.h"
#include <iostream>

#include "platformspecific.h"
#include <GLES2/gl2.h>

#include "gluafx.h"

Application::Application()
{
}

Application::~Application()
{
}

GLuint g_shaderProgram = 0;
GLuint g_vertexShader = 0;
GLuint g_fragmentShader = 0;

GLuint g_vertexBufferId = 0;
GLuint g_indexBufferId = 0;

GLfloat g_vertices[] = {
	0.0f, 0.5f, 0.0f,	0.0f, 1.0f, 0.0f, 1.0f,
    -0.5f, -0.5f, 0.0f,	0.0f, 0.0f, 1.0f, 1.0f,
	0.5f, -0.5f, 0.0f,	0.0f, 1.0f, 1.0f, 1.0f,
	0.5f, 0.5f, 0.0f,	1.0f, 1.0f, 1.0f, 1.0f,
};

GLuint g_indices[] = {
	1, 2, 0,
	1, 2, 3,
};

class EffectParser :
	public gluafx::EffectParser
{
	void onError(const std::string& message)
	{
		PLATFORM_BREAK(message);
	}

	void onBeginTechnique(const std::string& name)
	{
	}

	void onEndTechnique()
	{
	}

	void onBeginPass(const std::string& name)
	{
	}

	void onEndPass()
	{
		PLATFORM_ASSERT(g_vertexShader, "No vertex shader set!");
		PLATFORM_ASSERT(g_fragmentShader, "No pixel shader set");

		GLuint shaderProgramId = glCreateProgram();
		glAttachShader(shaderProgramId, g_vertexShader);
		glAttachShader(shaderProgramId, g_fragmentShader);
		glLinkProgram(shaderProgramId);

		GLint linkSucceeded;
		glGetProgramiv(shaderProgramId, GL_LINK_STATUS, &linkSucceeded);
		if (linkSucceeded != GL_TRUE)
		{
			const int c_maxLogBufferSize = 4096;
			char logBuffer[c_maxLogBufferSize];

			glGetProgramInfoLog(shaderProgramId, c_maxLogBufferSize, NULL, logBuffer);
			PLATFORM_BREAK("Failed to link shaderProgram: \n" << logBuffer);
		}

		g_shaderProgram = shaderProgramId;
	}

	void onVertexShader(const char* vertexShaderSource)
	{
		GLint compileSucceeded = GL_FALSE;
		const int c_maxLogBufferSize = 4096;
		char logBuffer[c_maxLogBufferSize];

		g_vertexShader = glCreateShader(GL_VERTEX_SHADER);

		const char* vertexShaderSourceArray[] = { vertexShaderSource };
		glShaderSource(g_vertexShader, sizeof(vertexShaderSourceArray) / sizeof(char*), vertexShaderSourceArray, NULL);
		glCompileShader(g_vertexShader);
		glGetShaderiv(g_vertexShader, GL_COMPILE_STATUS, &compileSucceeded);
		if (compileSucceeded != GL_TRUE)
		{
			glGetShaderInfoLog(g_vertexShader, c_maxLogBufferSize, NULL, logBuffer);
			PLATFORM_BREAK("Failed to compile vertex shader: \n" << logBuffer);
		}
	}

	void onFragmentShader(const char* pixelShaderSource)
	{
		GLint compileSucceeded = GL_FALSE;
		const int c_maxLogBufferSize = 4096;
		char logBuffer[c_maxLogBufferSize];

		const char* pixelShaderSourceArray[] = { pixelShaderSource };
		g_fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
		glShaderSource(g_fragmentShader, sizeof(pixelShaderSourceArray) / sizeof(char*), pixelShaderSourceArray, NULL);
		glCompileShader(g_fragmentShader);
		glGetShaderiv(g_fragmentShader, GL_COMPILE_STATUS, &compileSucceeded);
		if (compileSucceeded != GL_TRUE)
		{
			glGetShaderInfoLog(g_fragmentShader, c_maxLogBufferSize, NULL, logBuffer);
			PLATFORM_BREAK("Failed to compile vertex shader: \n" << logBuffer);
		}
	}
};

void
Application::init()
{
	::EffectParser effectParser;
	effectParser.parse("effect.gluafx");

	glGenBuffers(1, &g_vertexBufferId);
	glBindBuffer(GL_ARRAY_BUFFER, g_vertexBufferId);
	glBufferData(GL_ARRAY_BUFFER, sizeof(g_vertices), g_vertices, GL_STATIC_DRAW);

	glGenBuffers(1, &g_indexBufferId);
	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, g_indexBufferId);
	glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(g_indices), g_indices, GL_STATIC_DRAW);
}

void
Application::deinit()
{
}

void
Application::update(float dt)
{
}

void
Application::render()
{
    glClearDepthf(1.0f);
    glClearColor(1.0f, 0.0f, 0.0f, 1.0f);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

	glUseProgram(g_shaderProgram);
	glBindAttribLocation(g_shaderProgram, 0, "inPosition");
	glBindAttribLocation(g_shaderProgram, 1, "inColor");

	glBindBuffer(GL_ARRAY_BUFFER, g_vertexBufferId);
	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, g_indexBufferId);

	glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(float) * 7, 0);
	glEnableVertexAttribArray(0);
	glVertexAttribPointer(1, 4, GL_FLOAT, GL_FALSE, sizeof(float) * 7, (char*)0 + sizeof(float) * 3);
	glEnableVertexAttribArray(1);

	glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);

    glFlush();
}
